home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / machack / Hacks97 / BillBoot.sit / Bill Boot / source code / BillBoot.c < prev    next >
C/C++ Source or Header  |  1997-06-27  |  29KB  |  1,170 lines

  1. /*
  2.     File:        WinBoot.c
  3.     
  4.     Contains:    Hack to make the Mac boot sequence resemble
  5.                 a PC/Win95 boot sequence.
  6.  
  7.     Written by:    Eric Traut
  8.  
  9.     Date:        6/25/97
  10.  
  11. */
  12.  
  13.  
  14. #include <OSUtils.h>
  15. #include <Events.h>
  16. #include <Menus.h>
  17. #include <Quickdraw.h>
  18. #include <Dialogs.h>
  19. #include <TextEdit.h>
  20. #include <Devices.h>
  21. #include <Windows.h>
  22. #include <Fonts.h>
  23. #include <LowMem.h>
  24. #include <Gestalt.h>
  25. #include <Palettes.h>
  26. #include <Retrace.h>
  27. #include <Sound.h>
  28. #include <MixedMode.h>
  29. #include <Traps.h>
  30. #include <Processes.h>
  31. #include <QDOffscreen.h>
  32.  
  33. /* Static and Global Variables */
  34. static GDHandle            sMainDevice;
  35. static UInt16            sBitsPerPixel;
  36. static Rect                sRealDeviceRect;
  37. static Rect                sDeviceRect;
  38. static Ptr                sRealDeviceBasePtr;
  39. static Ptr                sDeviceBasePtr;
  40. static UInt32            sDeviceRowBytes;
  41. static UInt16            sTotalTextColumns;
  42. static UInt16            sTotalTextRows;
  43. static UInt16            sCurTextRow = 0;
  44. static Handle            sWin95SplashScreen = NULL;
  45. static Handle            sWin95Colors = NULL;
  46. static Handle            sPCFont = NULL;
  47. static Handle            sWin95BootSound = NULL;
  48. static UInt32            sNextStateChangeTicks;
  49. static UInt32            sCurrentDrawState;
  50. static UInt32            sCurrentDrawSubState;
  51. static UInt32            sMachineSpeed;
  52. static UInt32            sMachineMemory;
  53. static UInt32            sMachineType;
  54. static VBLTask            sVBLTask;
  55. static QDGlobals        myQd;
  56. static UniversalProcPtr    sOriginalLaunch;
  57. static UniversalProcPtr    sOriginalDMB;
  58. static UniversalProcPtr    sOriginalSetEntries;
  59. static SInt16            sPictWidth;
  60. static SInt16            sPictHeight;
  61. static SInt16            sHScale;
  62. static SInt16            sVScale;
  63. static Boolean            sLaunchPatchActive = true;
  64. static Boolean            sDMBPatchActive = true;
  65. static Boolean            sSetEntriesPatchActive = true;
  66. static Boolean            sVBLRunning = true;
  67. static UInt32             sLastInitName = 0;
  68. static SndChannelPtr    sSoundChannel = NULL;
  69.  
  70. /* Local Functions */
  71. static void        InitMac(void);
  72. static void        InstallVBL(void);
  73. static Boolean    InitScreenInfo(void);
  74. static void        LoadResources(void);
  75. static void        ApplyPatches(void);
  76. static void        InstallVBL(void);
  77. static void        DrawWin95SplashScreen(void);
  78. static void        DrawWin95ProgressBar(UInt8 inCurStage);
  79. static void        DrawDOSText(UInt16 inHPos, UInt16 inVPos, StringPtr inString, Boolean inInvert);
  80. static void        VBLDrawProc(VBLTaskPtr vblTaskPtr);
  81. static Boolean    DoMemoryTest(void);
  82. static void        TearDownHacks(void);
  83. static void        PlayWin95StartSound(void);
  84. static void        GetProcessorString(Str255 outProcString);
  85. static void        AppendPString(StringPtr ioStrA, StringPtr ioStrB);
  86. pascal OSErr    LaunchPatchProc(LaunchPBPtr LaunchParams);
  87. pascal void        DMBPatchProc(void);
  88. pascal void     SetEntriesPatch(short start, short count, CSpecArray aTable);
  89. static Boolean    HasNewInitName(Str63 outInitName);
  90. static void        DrawNewInitName(Str63 inInitName);
  91. static void        ScrollTextScreen(UInt16 inRows);
  92. static void        DoBillGatesAnimation(void);
  93.  
  94. /* Static Routine Descriptors */
  95. static RoutineDescriptor sVBLRD         = BUILD_ROUTINE_DESCRIPTOR(uppVBLProcInfo, &VBLDrawProc);
  96. static RoutineDescriptor sLaunchRD         = BUILD_ROUTINE_DESCRIPTOR(kPascalStackBased | RESULT_SIZE(kTwoByteCode) | STACK_ROUTINE_PARAMETER(1, kFourByteCode), &LaunchPatchProc);
  97. static RoutineDescriptor sDMBRD         = BUILD_ROUTINE_DESCRIPTOR(kPascalStackBased, &DMBPatchProc);
  98. static RoutineDescriptor sSetEntriesRD    = BUILD_ROUTINE_DESCRIPTOR(kPascalStackBased | STACK_ROUTINE_PARAMETER(1, kTwoByteCode) | STACK_ROUTINE_PARAMETER(2, kTwoByteCode) | STACK_ROUTINE_PARAMETER(3, kFourByteCode), &SetEntriesPatch);
  99.  
  100. /* Constant Definitions */
  101. enum
  102. {
  103.     kTextCellHSize            = 8,
  104.     kTextCellVSize            = 16,
  105.     
  106.     // Drawing states
  107.     kDrawBIOSMessage        = 0,
  108.     kDrawMemorySize,
  109.     kDrawStartingOS,
  110.     kDrawCDDriverText,
  111.     kMouseDriverText,
  112.     kBlinkCursor,
  113.     kDrawWin95Screen,
  114.     kAnimateWin95Screen,
  115.     
  116.     kProgressBarHeight        = 26,
  117.     kBillScrollAmount        = 8
  118. };
  119.  
  120. /*--------------------------------------------------------
  121.     main
  122.     
  123.     Main entry point to the INIT.
  124. --------------------------------------------------------*/
  125.  
  126. void
  127. main(void)
  128. {
  129.     // We need to initialize the Mac toolbox first
  130.     InitMac();
  131.     
  132.     // Next we'll blank the entire screen to prepare to
  133.     // make it look like a PC screen at boot time
  134.     if (InitScreenInfo())
  135.     {
  136.         // Next, we'll load our resource (fonts, PICTs, etc.
  137.         // so they are in memory when we need them).
  138.         LoadResources();
  139.         
  140.         // We need to temporarily patch out calls to QuickDraw
  141.         // so icons and other items in the boot sequence are
  142.         // not drawn on top of us.
  143.         ApplyPatches();
  144.         
  145.         // Initialize our state
  146.         sCurrentDrawState = kDrawBIOSMessage;
  147.         sNextStateChangeTicks = 0;
  148.         
  149.         // Finally, we'll install a VBL task to complete
  150.         // our boot sequence.
  151.         InstallVBL();
  152.         //TearDownHacks();
  153.     }
  154. }
  155.  
  156.  
  157. /*--------------------------------------------------------
  158.     InitMac
  159.     
  160.     Initializes the Mac toolbox.
  161. --------------------------------------------------------*/
  162.  
  163. void
  164. InitMac(void)
  165. {
  166.     long                        gestaltResult;
  167.     OSErr                        tempErr;
  168.  
  169.     // Get information about the CPU (type and speed)
  170.     tempErr = Gestalt(gestaltNativeCPUtype, &gestaltResult);
  171.     if (tempErr == noErr)
  172.         sMachineType = gestaltResult;
  173.     else
  174.         sMachineType = 0;
  175.     
  176.     tempErr = Gestalt('pclk', &gestaltResult);
  177.     if (tempErr == noErr)
  178.         sMachineSpeed = gestaltResult;
  179.     else
  180.         sMachineSpeed = 0;
  181.     
  182.     // Get information about memory (size of memory in Kb)
  183.     (void) Gestalt(gestaltPhysicalRAMSize, &gestaltResult);
  184.     sMachineMemory = gestaltResult / 1024L;
  185.  
  186.     InitGraf(&myQd.thePort);
  187. }
  188.  
  189.     
  190. /*--------------------------------------------------------
  191.     InitScreenInfo
  192.     
  193.     Determines the bounds of the main monitor and its
  194.     bit depth. If the depth is in the range we support,
  195.     it blanks the screen and returns true. Else it returns
  196.     false to indicate the INIT should just quietly do
  197.     nothing.
  198. --------------------------------------------------------*/
  199.  
  200. Boolean
  201. InitScreenInfo(void)
  202. {
  203.     PixMapHandle        devicePixMap;
  204.     
  205.     sMainDevice = GetMainDevice();
  206.     if (sMainDevice == NULL)
  207.         return false;
  208.     
  209.     devicePixMap = (**sMainDevice).gdPMap;
  210.     if (devicePixMap == NULL)
  211.         return false;
  212.     
  213.     // We currently only handle 8-bit for now
  214.     sBitsPerPixel = (**devicePixMap).pixelSize;
  215.     if (sBitsPerPixel != 8)
  216.         return false;
  217.     
  218.     // Stash away some information about the device
  219.     sDeviceRect = sRealDeviceRect = (**devicePixMap).bounds;
  220.  
  221.     // We don't support less than 640x480
  222.     if (sDeviceRect.right - sDeviceRect.left < 640 || sDeviceRect.bottom - sDeviceRect.top < 480)
  223.         return false;
  224.  
  225.     sDeviceBasePtr = sRealDeviceBasePtr = (**devicePixMap).baseAddr;
  226.     sDeviceRowBytes = (**devicePixMap).rowBytes & 0x3FFF;
  227.  
  228.     // Hide the cursor so we don't draw over it
  229.     HideCursor();
  230.  
  231.     return true;
  232. }
  233.     
  234.  
  235. /*--------------------------------------------------------
  236.     LoadResources
  237.     
  238.     Loads our resources into the system heap, then locks
  239.     them down so they don't move in the heap. We need to
  240.     be able to access these resources from interrupt time.
  241. --------------------------------------------------------*/
  242.  
  243. void
  244. LoadResources(void)
  245. {
  246.     SInt16            scrnWidth;
  247.     SInt16            scrnHeight;
  248.     
  249.     scrnWidth = sDeviceRect.right - sDeviceRect.left;
  250.     scrnHeight = sDeviceRect.bottom - sDeviceRect.top;
  251.     
  252.     // Make common screen sizes fit our constraints
  253.     if (scrnWidth >= 3 * 320 && scrnHeight >= 2 * 384)
  254.     {
  255.         sHScale = 3;
  256.         sVScale = 2;
  257.         sPictWidth = sHScale * 320;
  258.         sPictHeight = sVScale * 384;
  259.         sWin95SplashScreen = Get1Resource('SCRN', 128);
  260.     }
  261.     else if (scrnWidth >= 400 * 2 && scrnHeight >= 2 * 300)
  262.     {
  263.         sHScale = 2;
  264.         sVScale = 2;
  265.         sPictWidth = sHScale * 400;
  266.         sPictHeight = sVScale * 300;
  267.         sWin95SplashScreen = Get1Resource('SCRN', 129);
  268.     }
  269.     else
  270.     {
  271.         sHScale = 2;
  272.         sVScale = 2;
  273.         sPictWidth = sHScale * 320;
  274.         sPictHeight = sVScale * 240;
  275.         sWin95SplashScreen = Get1Resource('SCRN', 130);
  276.     }
  277.  
  278.     // Adjust the device rect
  279.     sDeviceRect.left += (scrnWidth - sPictWidth) / 2;
  280.     sDeviceRect.right -= (scrnWidth - sPictWidth) / 2;
  281.     sDeviceRect.top += (scrnHeight - sPictHeight) / 2;
  282.     sDeviceRect.bottom -= (scrnHeight - sPictHeight) / 2;
  283.     sDeviceBasePtr += (scrnWidth - sPictWidth) / 2 + 
  284.             (scrnHeight - sPictHeight) * sDeviceRowBytes;
  285.     if (sWin95SplashScreen == NULL)
  286.         DebugStr("\pCouldn't load splash screen");
  287.     
  288.     sTotalTextColumns = (sDeviceRect.right - sDeviceRect.left) / kTextCellHSize;
  289.     sTotalTextRows = (sDeviceRect.bottom - sDeviceRect.top) / kTextCellVSize;
  290.  
  291.     sWin95Colors = Get1Resource('SPLT', 128);
  292.     if (sWin95Colors == NULL)
  293.         DebugStr("\pCouldn't load color palette");
  294.     
  295.     sPCFont = Get1Resource('Font', 128);
  296.     if (sPCFont == NULL)
  297.         DebugStr("\pCouldn't load font bitmap");
  298.     
  299.     sWin95BootSound = Get1Resource('snd ', 128);
  300.     if (sWin95BootSound == NULL)
  301.         DebugStr("\pCouldn't load boot sound");
  302.     
  303.     DetachResource(sWin95SplashScreen);
  304.     MoveHHi(sWin95SplashScreen);
  305.     HLock(sWin95SplashScreen);
  306.     
  307.     DetachResource(sWin95Colors);
  308.     MoveHHi(sWin95Colors);
  309.     HLock(sWin95Colors);
  310.     
  311.     DetachResource(sPCFont);
  312.     MoveHHi(sPCFont);
  313.     HLock(sPCFont);
  314.     
  315.     DetachResource(sWin95BootSound);
  316.     MoveHHi(sWin95BootSound);
  317.     HLock(sWin95BootSound);
  318.  
  319.     DoBillGatesAnimation();
  320.  
  321.     if (sWin95Colors != NULL)
  322.     {
  323.         // Set up our palette for correct colors
  324.         SetGDevice(sMainDevice);
  325.         
  326.         // Turn our patch off momentarily so it takes effect
  327.         SetEntries(0, 255, (ColorSpec*)*sWin95Colors);
  328.     }
  329. }
  330.     
  331.  
  332. /*--------------------------------------------------------
  333.     ApplyPatches
  334.     
  335.     We need to prevent other INITs from drawing to the 
  336.     screen (that would spoil the effect). 
  337. --------------------------------------------------------*/
  338.  
  339. void
  340. ApplyPatches(void)
  341. {
  342.     PixMapHandle        devicePixMap;
  343.     
  344.     devicePixMap = (**sMainDevice).gdPMap;
  345.     if (devicePixMap == NULL)
  346.         return;
  347.     
  348.     // Point the base address of the main device
  349.     // to ROM so pixels are dropped in the bit bucket.
  350.     // Leave some slop to work around QD bugs.
  351.     (**devicePixMap).baseAddr = LMGetROMBase() + 1024;
  352.     
  353.     sOriginalLaunch = GetToolTrapAddress(_Launch);
  354.     SetToolTrapAddress(&sLaunchRD, _Launch);
  355.     
  356.     sOriginalDMB = GetToolTrapAddress(_DrawMenuBar);
  357.     SetToolTrapAddress(&sDMBRD, _DrawMenuBar);
  358.  
  359.     sOriginalSetEntries = GetToolTrapAddress(_SetEntries);
  360.     SetToolTrapAddress(&sSetEntriesRD, _SetEntries);
  361. }
  362.     
  363.  
  364. /*--------------------------------------------------------
  365.     InstallVBL
  366.     
  367.     Installs a VBL task we use to drive the animation
  368.     throughout the boot process.
  369. --------------------------------------------------------*/
  370.  
  371. void
  372. InstallVBL(void)
  373. {
  374.     sVBLTask.qLink = NULL;
  375.     sVBLTask.qType = vType;
  376.     sVBLTask.vblAddr = &sVBLRD;
  377.     sVBLTask.vblCount = 1;
  378.     sVBLTask.vblPhase = 0;
  379.     VInstall((QElemPtr)&sVBLTask);
  380. }
  381.  
  382.  
  383. /*--------------------------------------------------------
  384.     DrawWin95SplashScreen
  385.     
  386.     Draws the Win95 splash screen directly to the main
  387.     device.
  388. --------------------------------------------------------*/
  389.  
  390. void
  391. DrawWin95SplashScreen(void)
  392. {
  393.     UInt8*            curSrcPixel;
  394.     UInt8*            curDestRow;
  395.     UInt8*            curDestPixel;
  396.     UInt16            curRow;
  397.     UInt16            curCol;
  398.     
  399.     if (sWin95SplashScreen == NULL)
  400.         return;
  401.     
  402.     curSrcPixel = (UInt8*)*sWin95SplashScreen;
  403.     curDestPixel = curDestRow = (UInt8*)sDeviceBasePtr;
  404.     
  405.     for (curRow = 0; curRow < sPictHeight - kProgressBarHeight; curRow += sVScale)
  406.     {
  407.         for (curCol = 0; curCol < sPictWidth; curCol += sHScale)
  408.         {
  409.             UInt16                pixel;
  410.             
  411.             pixel = *curSrcPixel++;
  412.             
  413.             if (sHScale == 3)
  414.             {
  415.                 // Pixel double in vertical direction, pixel triple in horizontal
  416.                 curDestPixel[0] = pixel;
  417.                 curDestPixel[1] = pixel;
  418.                 curDestPixel[2] = pixel;
  419.                 curDestPixel[0 + sDeviceRowBytes] = pixel;
  420.                 curDestPixel[1 + sDeviceRowBytes] = pixel;
  421.                 curDestPixel[2 + sDeviceRowBytes] = pixel;
  422.             }
  423.             else
  424.             {
  425.                 // Pixel double in vertical direction, pixel double in horizontal
  426.                 curDestPixel[0] = pixel;
  427.                 curDestPixel[1] = pixel;
  428.                 curDestPixel[0 + sDeviceRowBytes] = pixel;
  429.                 curDestPixel[1 + sDeviceRowBytes] = pixel;
  430.             }
  431.  
  432.             curDestPixel += sHScale;
  433.         }
  434.         
  435.         curDestRow += sDeviceRowBytes * sVScale;
  436.         curDestPixel = curDestRow;
  437.     }
  438. }
  439.  
  440.  
  441. /*--------------------------------------------------------
  442.     DrawWin95ProgressBar
  443.     
  444.     Draws the Win95 progress bar on the bottom of the
  445.     screen.
  446. --------------------------------------------------------*/
  447.  
  448. void
  449. DrawWin95ProgressBar(UInt8 inCurStage)
  450. {
  451.     UInt8*            curDestRow;
  452.     UInt8*            curDestPixel;
  453.     UInt16            curRow;
  454.     UInt16            curCol;
  455.     
  456.     curDestPixel = curDestRow = (UInt8*)sDeviceBasePtr +
  457.                          sDeviceRowBytes * (sPictHeight - kProgressBarHeight);
  458.     
  459.     for (curRow = sPictHeight - kProgressBarHeight; curRow < sPictHeight; curRow++)
  460.     {
  461.         for (curCol = 0; curCol < sPictWidth; curCol += 4)
  462.         {
  463.             UInt32                pixel;
  464.             
  465.             // Determine which color index to use. Our color
  466.             // ramp is 0xF7 to 0xFD.
  467.             pixel = (curCol / (sPictWidth / 16)) + inCurStage;
  468.             if (pixel > 15)
  469.                 pixel -= 16;
  470.             if (pixel > 7)
  471.                 pixel = 15 - pixel;
  472.             pixel += 0xF7;
  473.             
  474.             pixel = (pixel << 24) + (pixel << 16) + (pixel << 8) + pixel;
  475.             
  476.             *(UInt32*)curDestPixel = pixel;
  477.             curDestPixel += 4;
  478.         }
  479.         
  480.         curDestRow += sDeviceRowBytes;
  481.         curDestPixel = curDestRow;
  482.     }
  483. }
  484.  
  485.  
  486. /*--------------------------------------------------------
  487.     DrawDOSText
  488.     
  489.     Draws the specified text at the h/v coordinate using
  490.     DOS characters. The coordinate is in text coordinates,
  491.     so 0,0 is the top, left-most cell on the screen.
  492. --------------------------------------------------------*/
  493.  
  494. void
  495. DrawDOSText(UInt16 inHPos, UInt16 inVPos, StringPtr inString, Boolean inInvert)
  496. {
  497.     UInt16            curCharIndex;
  498.     UInt8*            curSrcRow;
  499.     UInt8*            curSrcPixel;
  500.     UInt8*            curDestRow;
  501.     UInt8*            curDestPixel;
  502.     UInt16            curRow;
  503.     UInt16            curCol;
  504.     UInt8            curChar;
  505.     UInt8            invertMask;
  506.  
  507.     // Multiply by the cell size (accounting for pixel doubling)
  508.     inHPos *= kTextCellHSize;
  509.     inVPos *= kTextCellVSize;
  510.     
  511.     invertMask = inInvert ? 0xFF : 0x00;
  512.     
  513.     for (curCharIndex = 0; curCharIndex < inString[0]; curCharIndex++)
  514.     {
  515.         curChar = inString[curCharIndex + 1];
  516.         
  517.         // Determine source pointer to font graphic data
  518.         curSrcPixel = curSrcRow = (curChar - '!') * kTextCellHSize + (UInt8*)*sPCFont;
  519.         
  520.         // Determine destination location in video buffer
  521.         curDestPixel = curDestRow = (UInt8*)sDeviceBasePtr +
  522.                              sDeviceRowBytes * (UInt32)inVPos + inHPos;
  523.  
  524.         // We only have graphic information for characters in this range
  525.         if (curChar == ' ' || (curChar >= '!' && curChar <= '~'))
  526.         {
  527.             for (curRow = 0; curRow < kTextCellVSize; curRow++)
  528.             {
  529.                 if (curChar == ' ')
  530.                 {
  531.                     // For a space, clear the entire box
  532.                     for (curCol = 0; curCol < kTextCellHSize; curCol++)
  533.                         *curDestPixel++ = (0xFF ^ invertMask);
  534.                 }
  535.                 else
  536.                 {
  537.                     for (curCol = 0; curCol < kTextCellHSize; curCol++)
  538.                         *curDestPixel++ = (-*curSrcPixel++) ^ invertMask;
  539.                 }
  540.                 
  541.                 curDestRow += sDeviceRowBytes;
  542.                 curDestPixel = curDestRow;
  543.                 curSrcRow += ('~' - '!' + 1) * kTextCellHSize;
  544.                 curSrcPixel = curSrcRow;
  545.             }
  546.         }
  547.         
  548.         inHPos += kTextCellHSize;
  549.     }
  550. }
  551.  
  552.  
  553. /*--------------------------------------------------------
  554.     VBLDrawProc
  555.     
  556.     This is the VBL procedure that determines which state
  557.     we're in currently and calls the correct drawing
  558.     routine.
  559. --------------------------------------------------------*/
  560.  
  561. void
  562. VBLDrawProc(VBLTaskPtr vblTaskPtr)
  563. {
  564. #pragma unused (vblTaskPtr)
  565.     UInt32                curTicks;
  566.     Str255                processorString;
  567.     Str63                newInitName;
  568.     char                initChar;
  569.     
  570.     curTicks = LMGetTicks();
  571.     
  572.     if (curTicks >= sNextStateChangeTicks)
  573.     {
  574.         switch (sCurrentDrawState)
  575.         {
  576.         case kDrawBIOSMessage:
  577.             // Draw the BIOS text
  578.             DrawDOSText(1, sCurTextRow, "\pMacOS Toolbox BIOS", false);
  579.             DrawDOSText(sTotalTextColumns - 34, sCurTextRow++, 
  580.                             "\p(C) Apple Computer, Inc. 1984-97", false);
  581.             GetProcessorString(processorString);
  582.             DrawDOSText(1, sCurTextRow, processorString, false);
  583.             
  584.             // Progress to the next state after several ticks
  585.             sNextStateChangeTicks = curTicks + 10;
  586.             sCurrentDrawState = kDrawMemorySize;
  587.             sCurrentDrawSubState = 0;
  588.             break;
  589.         
  590.         case kDrawMemorySize:
  591.             if (DoMemoryTest())
  592.             {
  593.                 // Progress to the next state after several ticks
  594.                 sCurrentDrawState = kDrawStartingOS;
  595.                 sNextStateChangeTicks = curTicks + 60;
  596.             }
  597.             else
  598.             {
  599.                 // If we are not done testing memory, keep
  600.                 // going in this state for a while
  601.                 sNextStateChangeTicks = curTicks + 2;
  602.             }
  603.             break;
  604.         
  605.         case kDrawStartingOS:
  606.             sCurTextRow += 6;
  607.             DrawDOSText(1, sCurTextRow, "\pStarting MacOS 8.0...", false);
  608.             
  609.             // Progress to the next state almost immediately
  610.             sCurrentDrawState = kDrawCDDriverText;
  611.             sNextStateChangeTicks = curTicks + 20;
  612.             sCurrentDrawSubState = 15;
  613.             sCurTextRow += 2; 
  614.             break;
  615.         
  616.         case kDrawCDDriverText:
  617.             DrawDOSText(1, sCurTextRow, "\pApple CD-ROM Driver, Version 8.0 (SCSI001)", false);
  618.             DrawDOSText(1, sCurTextRow + 1, "\pLooking for CD-ROM Drive", (sCurrentDrawSubState & 0x1) == 0);
  619.  
  620.             if (--sCurrentDrawSubState == 0)
  621.             {
  622.                 // Progress to the next state after a while
  623.                 DrawDOSText(1, sCurTextRow + 1, "\pCD-ROM Drive Detected        ", false);
  624.                 sCurrentDrawState = kMouseDriverText;
  625.                 sCurTextRow += 3;
  626.             }
  627.             else
  628.             {
  629.                 sNextStateChangeTicks = curTicks + 20;
  630.             }
  631.             break;
  632.  
  633.         case kMouseDriverText:
  634.             DrawDOSText(1, sCurTextRow++, "\pMacOS Mouse Driver 8.0", false);
  635.             DrawDOSText(1, sCurTextRow++, "\pCopyright (C) Apple Computer, Inc. 1984-97", false);
  636.             DrawDOSText(1, sCurTextRow++, "\pStandard ADB Mouse Detected", false);
  637.             sCurTextRow++;
  638.             sCurrentDrawState = kBlinkCursor;
  639.             sNextStateChangeTicks = curTicks + 30;
  640.             sCurrentDrawSubState = 50000;
  641.             break;
  642.         
  643.         case kBlinkCursor:
  644.             // Has a new INIT been loaded since last time?
  645.             if (HasNewInitName(newInitName))
  646.             {
  647.                 DrawDOSText(1, sCurTextRow, "\p ", false);
  648.                 DrawNewInitName(newInitName);
  649.  
  650.                 if (sCurTextRow > sTotalTextRows - 4)
  651.                     ScrollTextScreen(2);
  652.                 else
  653.                     sCurTextRow += 2;
  654.                 
  655.                 // This is really gross, but if the current INIT
  656.                 // name is beyond the a certain point, we'll continue.
  657.                 initChar = ((sLastInitName >> 16) & 0xFF);
  658.                 if (initChar > 'a')
  659.                     initChar -= 'a' - 'A';
  660.                 if (initChar > 'S')
  661.                     sCurrentDrawState = kDrawWin95Screen;
  662.             }
  663.             
  664.             // Blink the cursor every 8th time
  665.             if ((sCurrentDrawSubState % 8) == 0)
  666.             {
  667.                 if ((sCurrentDrawSubState % 16) == 0)
  668.                     DrawDOSText(1, sCurTextRow, "\p_", false);
  669.                 else
  670.                     DrawDOSText(1, sCurTextRow, "\p ", false);
  671.             }
  672.  
  673.             if (--sCurrentDrawSubState == 0)
  674.                 sCurrentDrawState = kDrawWin95Screen;
  675.             break;
  676.             
  677.         case kDrawWin95Screen:
  678.             DrawWin95SplashScreen();
  679.  
  680.             // Progress to the next state immediately
  681.             sCurrentDrawState = kAnimateWin95Screen;
  682.             sCurrentDrawSubState = 0;
  683.             break;
  684.         
  685.         case kAnimateWin95Screen:
  686.             DrawWin95ProgressBar(sCurrentDrawSubState);
  687.  
  688.             // Keep animating every few ticks
  689.             sNextStateChangeTicks = curTicks + 6;
  690.             sCurrentDrawSubState++;
  691.             if (sCurrentDrawSubState > 15)
  692.                 sCurrentDrawSubState = 0;
  693.             break;
  694.  
  695.         }
  696.     }
  697.  
  698.     // Reprime the VBL task so we are called back again
  699.     sVBLTask.vblCount = 1;
  700. }
  701.  
  702.  
  703. /*--------------------------------------------------------
  704.     DoMemoryTest
  705.     
  706.     Draws the memory test text to the DOS screen. Returns
  707.     true once the memory test is complete.
  708. --------------------------------------------------------*/
  709.  
  710. Boolean
  711. DoMemoryTest(void)
  712. {
  713.     Str31            memorySizeText;
  714.     UInt16            curCharIndex;
  715.     UInt32            memorySize;
  716.     
  717.     // Clear out the string
  718.     for (curCharIndex = 0; curCharIndex < 10; curCharIndex++)
  719.         memorySizeText[curCharIndex] = ' ';
  720.     
  721.     // Construct the memory size string
  722.     memorySizeText[9] = 'K';
  723.     memorySizeText[0] = 9;
  724.     
  725.     memorySize = sCurrentDrawSubState;
  726.     
  727.     for (curCharIndex = 8; curCharIndex > 0; curCharIndex--)
  728.     {
  729.         memorySizeText[curCharIndex] = (memorySize % 10) + '0';
  730.         
  731.         memorySize /= 10;
  732.         if (memorySize == 0)
  733.             break;
  734.     }
  735.     
  736.     // Draw the new text
  737.     DrawDOSText(1, 4, memorySizeText, false);
  738.     
  739.     // Add one megabyte (1024Kb) to the state
  740.     sCurrentDrawSubState += 1024;
  741.     
  742.     // Did we report all the memory?
  743.     return (sCurrentDrawSubState > sMachineMemory);
  744. }
  745.  
  746.  
  747. /*--------------------------------------------------------
  748.     TearDownHacks
  749.     
  750.     Removes the VBL task, patches, etc.
  751. --------------------------------------------------------*/
  752.  
  753. void
  754. TearDownHacks(void)
  755. {
  756.     PixMapHandle        devicePixMap;
  757.     
  758.     // Restore the real base address of the main device
  759.     devicePixMap = (**sMainDevice).gdPMap;
  760.     if (devicePixMap == NULL)
  761.         return;
  762.     
  763.     (**devicePixMap).baseAddr = sRealDeviceBasePtr;
  764.     
  765.     VRemove((QElemPtr)&sVBLTask);
  766.  
  767.     RestoreDeviceClut(sMainDevice);
  768.     sSetEntriesPatchActive = false;
  769.     ShowCursor();
  770. }
  771.  
  772.  
  773. /*--------------------------------------------------------
  774.     PlayWin95StartSound
  775.     
  776.     Plays the Win95 start wound asynchronously.
  777. --------------------------------------------------------*/
  778.  
  779. void
  780. PlayWin95StartSound(void)
  781. {
  782.     if (sSoundChannel != NULL)
  783.         (void) SndPlay(sSoundChannel, (SndListHandle)sWin95BootSound, true);
  784. }
  785.  
  786.  
  787. /*--------------------------------------------------------
  788.     GetProcessorString
  789.     
  790.     Returns an ASCII string that describes the speed
  791.     and type of processor.
  792. --------------------------------------------------------*/
  793.  
  794. void
  795. GetProcessorString(Str255 outProcString)
  796. {
  797.     UInt32                mhz;
  798.     
  799.     outProcString[0] = 3;
  800.     outProcString[1] = ' ';
  801.     outProcString[2] = ' ';
  802.  
  803.     // Convert speed from Hz to MHz (rounding if necessary)
  804.     mhz = (sMachineSpeed + 500000L) / 1000000L;
  805.     
  806.     outProcString[3] = (mhz % 10) + '0';
  807.     mhz /= 10;
  808.     if (mhz > 0)
  809.         outProcString[2] = (mhz % 10) + '0';
  810.     mhz /= 10;
  811.     if (mhz > 0)
  812.         outProcString[1] = (mhz % 10) + '0';
  813.     
  814.     AppendPString(outProcString, "\pMHz ");
  815.     
  816.     switch (sMachineType)
  817.     {
  818.     case gestaltCPU601:
  819.         AppendPString(outProcString, "\pPowerPC 601");
  820.         break;
  821.     
  822.     case gestaltCPU603:
  823.         AppendPString(outProcString, "\pPowerPC 603");
  824.         break;
  825.     
  826.     case gestaltCPU604:
  827.         AppendPString(outProcString, "\pPowerPC 604");
  828.         break;
  829.     
  830.     case 0x106:
  831.         AppendPString(outProcString, "\pPowerPC 603e");
  832.         break;
  833.     
  834.     case 0x107:
  835.         AppendPString(outProcString, "\pPowerPC 603ev");
  836.         break;
  837.     
  838.     case 0x108:
  839.         AppendPString(outProcString, "\pPowerPC 740");
  840.         break;
  841.     
  842.     case 0x109:
  843.         AppendPString(outProcString, "\pPowerPC 604e");
  844.         break;
  845.     
  846.     case 0x10A:
  847.         AppendPString(outProcString, "\pPowerPC 760");
  848.         break;
  849.     
  850.     default:
  851.         AppendPString(outProcString, "\pUnknown Processor");
  852.         break;
  853.     }
  854. }
  855.  
  856.  
  857. /*--------------------------------------------------------
  858.     AppendPString
  859.     
  860.     Appends one pascal string onto a second.
  861. --------------------------------------------------------*/
  862.  
  863. void
  864. AppendPString(StringPtr ioStrA, StringPtr ioStrB)
  865. {
  866.     UInt16            curStrIndex;
  867.     
  868.     for (curStrIndex = 0; curStrIndex < ioStrB[0]; curStrIndex++)
  869.         ioStrA[ioStrA[0] + curStrIndex + 1] = ioStrB[curStrIndex + 1];
  870.  
  871.     ioStrA[0] += ioStrB[0];
  872. }
  873.  
  874.  
  875. /*--------------------------------------------------------
  876.     LaunchPatchProc
  877.     
  878.     Patch for the _Launch trap.
  879. --------------------------------------------------------*/
  880.  
  881. pascal OSErr
  882. LaunchPatchProc(LaunchPBPtr launchParams)
  883. {
  884.     OSErr            tempErr;
  885.     
  886.     // Disable ourselves now
  887.     if (sLaunchPatchActive)
  888.     {
  889.         THz        oldZone;
  890.         
  891.         oldZone = GetZone();
  892.         SetZone(SystemZone());
  893.         
  894.         // Allocate a sound channel so we can call the start sound
  895.         (void) SndNewChannel(&sSoundChannel, squareWaveSynth, 0, NULL);
  896.  
  897.         SetZone(oldZone);
  898.  
  899.         PlayWin95StartSound();
  900.     }
  901.     
  902.     sLaunchPatchActive = false;
  903.     
  904.     // Chain through to the caller
  905.     tempErr = CallUniversalProc((UniversalProcPtr)sOriginalLaunch,
  906.                                 kPascalStackBased | RESULT_SIZE(kTwoByteCode) | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  907.                                 launchParams);
  908.  
  909.     return tempErr;
  910. }
  911.  
  912.  
  913. /*--------------------------------------------------------
  914.     DMBPatchProc
  915.     
  916.     Patch for the _DrawMenuBar trap.
  917. --------------------------------------------------------*/
  918.  
  919. pascal void
  920. DMBPatchProc(void)
  921. {
  922.     // Disable ourselves now
  923.     if (!sLaunchPatchActive && sDMBPatchActive)
  924.     {
  925.         TearDownHacks();
  926.         sDMBPatchActive = false;
  927.     }
  928.     
  929.     // Chain through to the caller
  930.     (void) CallUniversalProc((UniversalProcPtr)sOriginalDMB, kPascalStackBased);
  931. }
  932.  
  933.  
  934. /*--------------------------------------------------------
  935.     SetEntriesPatch
  936.     
  937.     Prevents the system from taking over the clut while
  938.     we're installed
  939. --------------------------------------------------------*/
  940.  
  941. pascal void 
  942. SetEntriesPatch(short start, short count, CSpecArray aTable)
  943. {
  944.     if (!sSetEntriesPatchActive)
  945.     {
  946.         // Call through to original
  947.         (void) CallUniversalProc((UniversalProcPtr)sOriginalSetEntries,
  948.                 kPascalStackBased | 
  949.                     STACK_ROUTINE_PARAMETER(1, kTwoByteCode) |
  950.                     STACK_ROUTINE_PARAMETER(2, kTwoByteCode) |
  951.                     STACK_ROUTINE_PARAMETER(3, kFourByteCode),
  952.                 start,
  953.                 count,
  954.                 aTable);
  955.     }
  956. }
  957.  
  958.  
  959. /*--------------------------------------------------------
  960.     HasNewInitName
  961.     
  962.     Determines whether there is a new INIT loading
  963.     since the last time we checked. If a new INIT is
  964.     being loaded since the last time we were called,
  965.     we return true.
  966. --------------------------------------------------------*/
  967.  
  968. Boolean
  969. HasNewInitName(Str63 outInitName)
  970. {
  971.     StringPtr            curInitName;
  972.     UInt16                curChar;
  973.     Boolean                initChanged = false;
  974.     
  975.     curInitName = *(StringPtr*)0x914;
  976.     
  977.     // Make sure there is a valid INIT name hanging off of 0x914
  978.     if (*(UInt32*)0x910 == 0xFFFFFFFF && 
  979.         (UInt32)curInitName != 0xFFFFFFFF &&
  980.         ((UInt32)curInitName & 0x3) == 0 &&
  981.         (SInt32)curInitName > 0)
  982.     {
  983.         curInitName = *(StringPtr*)0x914;
  984.         
  985.         if (curInitName[0] >= 4 && sLastInitName != *(UInt32*)curInitName)
  986.         {
  987.             // Copy the current INIT name to our output. Since we're
  988.             // being called at interrupt time, it's possible the name
  989.             // is only partially copied, but it's most likely intact.
  990.             for (curChar = 0; curChar <= curInitName[0]; curChar++)
  991.                 outInitName[curChar] = curInitName[curChar];
  992.             
  993.             // Record the first four bytes so we can tell when it changes
  994.             sLastInitName = *(UInt32*)curInitName;
  995.             initChanged = true;
  996.         }
  997.     }
  998.     
  999.     return initChanged;
  1000. }
  1001.  
  1002.  
  1003. /*--------------------------------------------------------
  1004.     DrawNewInitName
  1005.     
  1006.     Outputs a message at the current line describing
  1007.     the INIT being loaded.
  1008. --------------------------------------------------------*/
  1009.  
  1010. void
  1011. DrawNewInitName(Str63 inInitName)
  1012. {
  1013.     DrawDOSText(1, sCurTextRow, "\pLoading driver ", false);
  1014.     DrawDOSText(16, sCurTextRow, inInitName, false);
  1015. }
  1016.  
  1017.  
  1018. /*--------------------------------------------------------
  1019.     ScrollTextScreen
  1020.     
  1021.     Scrolls the entire text buffer up the specified
  1022.     number of rows.
  1023. --------------------------------------------------------*/
  1024.  
  1025. void
  1026. ScrollTextScreen(UInt16 inRows)
  1027. {
  1028.     UInt32*            curSrc;
  1029.     UInt32*            curDest;
  1030.     UInt32*            curSrcRow;
  1031.     UInt32*            curDestRow;
  1032.     UInt16            curColumn;
  1033.     UInt16            curRow;
  1034.     
  1035.     curSrcRow = curSrc = (UInt32*)(sDeviceBasePtr + sDeviceRowBytes * inRows * kTextCellVSize);
  1036.     curDestRow = curDest = (UInt32*)sDeviceBasePtr;
  1037.     
  1038.     for (curRow = 0; curRow < sTotalTextRows * kTextCellVSize; curRow++)
  1039.     {
  1040.         if (curRow >= (sTotalTextRows - inRows) * kTextCellVSize)
  1041.         {
  1042.             // Fill in last few rows with black
  1043.             for (curColumn = 0; curColumn < sTotalTextColumns * kTextCellHSize; curColumn += 4)
  1044.                 *curDest++ = 0xFFFFFFFF;
  1045.         }
  1046.         else
  1047.         {
  1048.             for (curColumn = 0; curColumn < sTotalTextColumns * kTextCellHSize; curColumn += 4)
  1049.                 *curDest++ = *curSrc++;
  1050.         }
  1051.         
  1052.         curSrcRow = (UInt32*)((UInt8*)curSrcRow + sDeviceRowBytes);
  1053.         curDestRow = (UInt32*)((UInt8*)curDestRow + sDeviceRowBytes);
  1054.         curSrc = curSrcRow;
  1055.         curDest = curDestRow;
  1056.     }
  1057. }
  1058.  
  1059.  
  1060. /*--------------------------------------------------------
  1061.     DoBillGatesAnimation
  1062.     
  1063.     Scrolls the Mac screen off to the right while Bill
  1064.     Gates pushes it.
  1065. --------------------------------------------------------*/
  1066.  
  1067. void
  1068. DoBillGatesAnimation(void)
  1069. {
  1070.     GDHandle        savedGD;
  1071.     CGrafPtr        savedPort;
  1072.     CGrafPtr        wMgrPort;
  1073.     Rect            curRect;
  1074.     Rect            billRect;
  1075.     Rect            billEraseRect;
  1076.     UInt32            lastTicks;
  1077.     RgnHandle        dummyRgn;
  1078.     PicHandle        billPict1;
  1079.     PicHandle        billPict2;
  1080.     PicHandle        billPict3;
  1081.     PicHandle        curBillPict;
  1082.     UInt8            curStage = 0;
  1083.     UInt32            scrnWidth;
  1084.     UInt8            bobStep = 0;
  1085.     
  1086.     billPict1 = GetPicture(128);
  1087.     billPict2 = GetPicture(129);
  1088.     billPict3 = GetPicture(130);
  1089.     curBillPict = billPict1;
  1090.     
  1091.     billRect = (*billPict1)->picFrame;
  1092.     OffsetRect(&billRect, -billRect.right, -billRect.bottom + sRealDeviceRect.bottom);
  1093.     billEraseRect = billRect;
  1094.     billEraseRect.right = billEraseRect.left;
  1095.     billEraseRect.left = billEraseRect.right - kBillScrollAmount - 4;
  1096.     
  1097.     GetGWorld(&savedPort, &savedGD);
  1098.     GetCWMgrPort(&wMgrPort);
  1099.     SetGWorld(wMgrPort, sMainDevice);
  1100.     
  1101.     // Fill in background with black
  1102.     BackColor(blackColor);
  1103.     curRect = sRealDeviceRect;
  1104.     lastTicks = TickCount();
  1105.     dummyRgn = NewRgn();
  1106.  
  1107.     scrnWidth = sRealDeviceRect.right - sRealDeviceRect.left;
  1108.     
  1109.     while (billRect.left < curRect.right)
  1110.     {
  1111.         ScrollRect(&curRect, kBillScrollAmount, 0, dummyRgn);
  1112.         DrawPicture(curBillPict, &billRect);
  1113.         EraseRect(&billEraseRect);
  1114.         
  1115.         OffsetRect(&billRect, kBillScrollAmount, bobStep >= 4 ? -2 : 2);
  1116.         billEraseRect.right += kBillScrollAmount;
  1117.         curRect.left += kBillScrollAmount;
  1118.         bobStep++;
  1119.         if (bobStep >= 8)
  1120.             bobStep = 0;
  1121.         
  1122.         // Add a small delay so we don't move too fast
  1123.         while (TickCount() <= lastTicks + 2) {};
  1124.         lastTicks = TickCount();
  1125.         
  1126.         switch (curStage)
  1127.         {
  1128.         case 0:
  1129.             if (curRect.left >= 6 * scrnWidth / 10)
  1130.             {
  1131.                 curBillPict = billPict2;
  1132.                 curStage++;
  1133.             }
  1134.             break;
  1135.         
  1136.         case 1:
  1137.             if (curRect.left >= 7 * scrnWidth / 10)
  1138.             {
  1139.                 curBillPict = billPict3;
  1140.                 curStage++;
  1141.             }
  1142.             break;
  1143.         
  1144.         case 2:
  1145.             if (curRect.left >= 8 * scrnWidth / 10)
  1146.             {
  1147.                 curBillPict = billPict2;
  1148.                 curStage++;
  1149.             }
  1150.             break;
  1151.         
  1152.         case 3:
  1153.             if (curRect.left >= 9 * scrnWidth / 10)
  1154.             {
  1155.                 curBillPict = billPict1;
  1156.                 curStage++;
  1157.             }
  1158.             break;
  1159.         }
  1160.     }
  1161.     
  1162.     EraseRect(&sRealDeviceRect);
  1163.     DisposeRgn(dummyRgn);
  1164.     SetGWorld(savedPort, savedGD);
  1165. }
  1166.  
  1167.  
  1168.  
  1169.  
  1170.